\chapter{Metrics}
Software metrics can be applied to classes and modules within the CEAB++ to gain
insight into various performance characteristics and quality of the system.
These insights may then be used to draw conclusions and, in turn, may result in
the improvement of the software. 

Conversely, basic mathematical and classification models may
over-simplify complex processes and behaviours--potentially leading to decisions
which are based on erroneous conclusions. This section applies basic metrics
to the stability, responsibility, dependency and the level of abstraction of the
CEAB++ software system. The metrics are used to draw conclusions wherever
possible, but consideration is also given to the assumptions inherent in the
model, and their effects on the conclusions provided by the metrics.

The majority of the metrics depend on the afferent (coupling into) and efferent 
(coupling out of) dependencies of classes. Figure \ref{fig:couplings}
graphically depicts the dependencies of the major classes and packages of the
CEAB++. Their afferent and efferent couplings are listed in Table
\ref{tab:couplings}.

\begin{figure}[!ht]
    \begin{center}
        \includegraphics[width=\textwidth]{images/ClassDependencies.png}
    \end{center}
    \caption{Class Dependencies}
    \label{fig:couplings}
\end{figure}

\begin{table}
    \centering
    \begin{tabular}{| c | c | c |}
        \hline
        \textbf{Class} & \textbf{Afferent Couplings} & \textbf{Efferent
        Couplings} \\ \hline
        Course & 8 & 0 \\ \hline
        Plan & 3 & 1 \\ \hline
        PlannedCourse & 2 & 2 \\ \hline
        Schedule & 1 & 3 \\ \hline
        Offering & 3 & 1 \\ \hline
        Timeslot & 2 & 2 \\ \hline
        Student & 0 & 8 \\ \hline
        DegreeRequirement & 1 & 3 \\ \hline
    \end{tabular}
    \caption{Afferent and Efferent Couplings}
    \label{tab:couplings}
\end{table}

\section{Stability}
% Stability is a measure of how likely a model is to change, and/or how
% frequently a model changes.

The stability of a module may be partially based on its inherent behaviour, but
it may also be a function of the external forces which act upon the module.
Thus, one method of viewing the stability of a module is to consider its
coupling--both afferent (coupling into) and efferent (coupling out of) the
module.

The stability is given as~\cite{ref:csnotes}:

\begin{equation}
stability(M) = \frac{A_m}{A_m + E_m} \\
\end{equation}

Where $A_m$ is the number of afferent couplings, and $E_m$ is the number of
efferent couplings.

Based on Table \ref{tab:couplings}, the stability of each class is shown in
table \ref{tab:stability}.

\begin{table}
    \centering
    \begin{tabular}{| c | c |}
        \hline
        \textbf{Class} & \textbf{Stability} \\ \hline
        Course & 1 \\ \hline
        Plan & 0.75  \\ \hline
        PlannedCourse & 0.5 \\ \hline
        Schedule & 0.25 \\ \hline
        Offering & 0.75 \\ \hline
        Timeslot & 0.5 \\ \hline
        Student & 0 \\ \hline
        DegreeRequirement & 0.25 \\ \hline
    \end{tabular}
    \caption{Stabilities for Major Classes}
    \label{tab:stability}
\end{table}

Based on this analysis, the Course class is the most stable,
while the Student class is the least stable class. This makes 
good design sense, as the idea
of a course is quite stable, while the capabilities of a Student will constantly
change as the functionality of the software evolves. Plans and Schedules fall
into the middle of the pack when it comes to stability, as they require Courses
(the most stable class), but Students (the least stable class) require them.

\section{Responsibility}
A parent module is responsible for the classes which depend on it. Accordingly,
a parent module's responsibility is proportional to the number of classes which depend
on the parent module. A measure of a module's responsibility is given
by~\cite{ref:csnotes}:

\begin{equation}
responsibility(M) = \frac{A_m - A_{min}}{A_{max} - A_{min}} \\
\end{equation}

Where $A_m$ is the number of afferent couplings in the class or module, and
$A_{min}$ and $A_{max}$ are the maximum and minimum of afferent couplings in the
system, respectively.

Table \ref{tab:responsibility} shows the responsibility for each class.

\begin{table}
    \centering
    \begin{tabular}{| c | c |}
        \hline
        \textbf{Class} & \textbf{Responsibility} \\ \hline
        Course & 1  \\ \hline
        Plan & 0.38  \\ \hline
        PlannedCourse & 0.25  \\ \hline
        Schedule & 0.14   \\ \hline
        Offering & 0.38  \\ \hline
        Timeslot & 0.25  \\ \hline
        Student & 0 \\ \hline
        DegreeRequirement &  0.13 \\ \hline
    \end{tabular}
    \caption{Responsibilities for Major Classes}
    \label{tab:responsibility}
\end{table}

Again, the responsibilities make sense. Courses are the most responsible, with
students being the least responsible. This does mean however, that any changes
to the Course class could have extremely large repercussions, as it is both very
stable and very responsible. Due to this level of responsibility, adding new
classes might be more favourable than modifying the existing Course class if
changes need to be made in the future. It is encouraging that all of the other
classes however have responsibilities that are less than $0.5$. This is due to
the separation of the Schedule and Plan packages, keeping either from being
responsible for the other.

\section{Level of Abstraction}
Python does not support abstract interfaces due to its dynamic nature, so this
section is not relevant to the discussion on metrics.
% Consider if the module/class
    % Has pure virtual functions
    % Is an interface
    % defines a prototype
    % depends on no other class or module

\section{Dependency}
In contrast with a module's responsibility---which measures the number of classes
which depend on the module---dependency measures the number of classes or
modules on which the current module is dependent. As with responsibility, this
is done by making a measurement relative to the rest of the
system~\cite{ref:csnotes}:

\begin{equation}
dependency(M) = \frac{E_m - E_{min}}{E_{max} - E_{min}} \\
\end{equation}

Where $E_m$ is the number of efferent couplings in the class or module, and
$E_{min}$ and $E_{max}$ are the maximum and minimum of afferent couplings in the
system, respectively.

Table \ref{tab:dependency} shows the dependency values for the major classes.

\begin{table}
    \centering
    \begin{tabular}{|c | c |}
        \hline
        \textbf{Class} & \textbf{Dependency} \\ \hline
        Course & 0  \\ \hline
        Plan &  0.13 \\ \hline
        PlannedCourse &  0.25 \\ \hline
        Schedule &  0.38 \\ \hline
        Offering & 0.13 \\ \hline
        Timeslot &  0.25 \\ \hline
        Student &  1 \\ \hline
        DegreeRequirement &  0.38 \\ \hline
    \end{tabular}
    \caption{Dependency of Major Classes}
    \label{tab:dependency}
\end{table}

Again, a common trend can be observed wherein the Course class has no dependency while the
Student class depends on all of the other classes. The other classes have
dependency values less than $0.5$ which is encouraging, and again due to the
decoupling of the Schedule and Plan packages.

\section{Profiling and Optimization}

%how to tie metrics into profiling ?

Several profiling tools were used to describe and analyze run time performance.
Profiling middleware was used to obtain data on execution time and the number of
function calls (both recursive and primitive) associated with each view.
Further, statistics using tools such as PyMetrics were generated against certain
modules, as shown in Table \ref{tab:planmetrics}.

\begin{table}
    \centering
    \begin{tabular}{|c|c|}
        \hline
        \textbf{Metric} & \textbf{Count} \\ \hline
            maxBlockDepth & 3 \\ \hline
            numBlocks & 26 \\ \hline
            numCharacters & 7710 \\ \hline
            numComments & 15 \\ \hline
            numCommentsInline & 1 \\ \hline
            numFunctions & 12 \\ \hline
            numKeywords & 90 \\ \hline
            numLines & 225 \\ \hline
            numMultipleExitFcns & 5 \\ \hline
            numTokens & 1938 \\ \hline
    \end{tabular}
    \caption{Basic Metrics for /plans/views.py}
    \label{tab:planmetrics}
\end{table}


Through these profiling tools, it was observed that the number of SQL queries on
the plans view was particularly high. Upon further inspection, several changes
were made to reduce the query count. These changes involved the retrieval of
query sets and the use of database aggregation functions over excessive fetching
and looping.
 
For instance, rather than performing a new query on each loop, a join was used
to retrieve all information in the original query. This prevents looping over
the queryset, performing a whole query every time. Further performance
optimizations were made, such as in the treatment of CEAB hours. Unlike
technical electives, there is no discrimination between the number of CSE hours in
each category as, in contrast to the TSEs, which are segregated into various
buckets--sci, math, engdes, and engsci.

Moreover, in several cases, the query result was stored in a variable and
subsequently referenced, instead of performing the same query multiple times.
These measures helped to decrease the query count from 61 to 16.

